<?php
namespace DRY\Persistence;

/**
 * DonReY Framework 2012 :: Module component: Persistence Container Cookie
 *
 * Container that stores data in HTTP Cookies (per user, available even if user closes browser) - One cookie per container.
 * It encodes data in JSON format prior to sending it to the browser (It may be retrieved by the browser and decoded there directly)
 * This is a non-shared container which doesn't need an owner set.
 *
 * @author Wavetrex <wavetrex@gmail.com>
 * @link http://www.donrey.net/Documentation/Structure/Modules/persistence.html
 * @license [GPL v3] http://www.gnu.org/licenses/gpl-3.0.html
 * @version 1.0.dev
 * @package DonReY
 * @subpackage Module.Persistence
 */
class Container_Cookie extends Container_base
{

	/**
	 * Cookie container config
	 * @var SimpleXMLElement
	 */
	protected $CFG;

	/**
	 * Cookie cache - Contains the values of this container until the destructor runs ( which actually sends the cookie )
	 * @var array
	 */
	private $_cache = array();

	/**
	 * Cookie Global init, nothing to do here.
	 * @return bool True
	 */
	static public function global_Init()
	{
		// nothing to initialize for cookies
		self::$_initialized['cookie']=true;
		return true;
	}

	/**
	 * Captures the script output when using this container, since cookies can only be set if the headers have not yet been set
	 * @param string $name
	 */
	public function __construct($name, $persistence_alias, $CFG)
	{
		$this-> CFG = $CFG;
		if(isset($_COOKIE[$name]))
			$this->_cache = json_decode($_COOKIE[$name], true);
		ob_start();
		parent::__construct($name);
	}

	/**
	 * Destructor for cookie container:
	 * - creates the cookie that stores the container
	 * - or expires cookie when container is empty
	 */
	public function __destruct()
	{
		if(empty($this->_cache))
				setrawcookie($this->_name, null, time()-31536000, '/');
		else {
			// data is encoded in cookie using JSON ( so it can be easy obtained in the javascript part )
			$json_cookie = str_replace(
				array(",",";"," ","\t","\r","\n","\013","\014"),
				array("%2C","%3B","%20","%09","%0D","%0A","%0B","%0C"),
				json_encode($this->_cache, JSON_FORCE_OBJECT)
			);
			setrawcookie($this->_name, $json_cookie, isset($this-> CFG['maxlife'])?time()+ $this-> CFG['maxlife']:0, '/');
		}
		ob_end_flush();
	}

	/**
	 * Implementation of __get for the cookie container
	 *
	 * @param string $varname
	 */
	public function &__get($varname)
	{
		// to avoid creating a new key in $_COOKIE for the inexistent variable (when attempting to read it)
		if(array_key_exists($varname, $this->_cache) || $varname=="__expiry")
			return $this->_cache[$varname];
		else {
			$null = null;
			return $null;
		}
	}

	/**
	 * Implementation of __set for the cookie container
	 *
	 * @param string $varname
	 * @param mixed $value
	 */
	public function __set($varname, $value)
	{
		$this->_cache[$varname] = $value;
	}

	/**
	 * Implementation of __isset for the cookie container
	 *
	 * @param string $varname
	 * @return bool
	 */
	public function __isset($varname)
	{
		return array_key_exists($varname, $this->_cache);
	}

	/**
	 * Implementation of __unset for the cookie container
	 *
	 * @param string $varname
	 */
	public function __unset($varname)
	{
		unset($this->_cache[$varname]);
	}

	/**
	 * Implementation of template Countable for the cookie container
	 *
	 * @return int
	 */
	public function count()
	{
		return count($this->_cache);
	}

	/**
	 * Implementation of destroy() for the cookie container
	 */
	public function destroy()
	{
		$this->_cache = array();
	}

	/**
	 * Implementation of read_all() for the cookie container
	 *
	 * @return array
	 */
	public function &read_All()
	{
		if(isset($this->__expiry)) { // if expiry was implemented, you cannot return var directly...
			$ret = $this->_cache; // make a copy
			unset($ret['__expiry']); // remove the special variable ( actually PHP makes a copy only here... )
			return $ret;
		} else
			return $this->_cache;
	}

}
?>